A:
我对整个过程不理解的点在于,ActivityJpaRepository的防腐层做在哪,从聚合根repository到 jpa repository,这个过程设计是否合理了,还有就是ActivityJpaRepository里面的写法是否都正确了Q:
非常好的问题!你提出了 DDD 架构中非常核心的设计疑问。让我详细分析:
问题 1:防腐层在哪里?设计是否合理?
📊 当前的三层架构
┌─────────────────────────────────────────────────────────────┐
│ Domain 层(业务核心) │
│ IActivityAggregateRepository (接口) │
│ - 定义业务需要的持久化能力 │
│ - 使用领域对象:ActivityAggregate, ActivityId │
│ - 不关心技术实现 │
└─────────────────────────────────────────────────────────────┘
↑ implements
┌─────────────────────────────────────────────────────────────┐
│ Infrastructure/Adapter 层(适配器 - 第一层防腐) │
│ ActivityAggregateRepository (实现类) │
│ - 实现领域接口 │
│ - 转换:ActivityAggregate ↔ ActivityPO │
│ - 协调:调用 JPA Repository │
│ ⚠️ 这里是第一层防腐层:隔离领域模型和持久化模型 │
└─────────────────────────────────────────────────────────────┘
↓ uses
┌─────────────────────────────────────────────────────────────┐
│ Infrastructure/DAO 层(数据访问 - 第二层防腐) │
│ ActivityJpaRepository (JPA 接口) │
│ - 封装 Spring Data JPA 框架 │
│ - 操作数据库表 │
│ ⚠️ 这里是第二层防腐层:隔离 JPA 框架和业务代码 │
└─────────────────────────────────────────────────────────────┘
↓ operates
Database🎯 两层防腐层的设计
第一层防腐:ActivityAggregateRepository
java
// 防腐点 1:隔离领域模型和持久化模型
public class ActivityAggregateRepository implements IActivityAggregateRepository {
private final ActivityJpaRepository activityRepository;
private final ActivityConverter activityConverter; // 关键:转换器
@Override
public void save(ActivityAggregate aggregate) {
// 🛡️ 防腐:Aggregate → PO
ActivityPO activityPO = activityConverter.aggregateToPO(aggregate);
// 调用 JPA Repository
activityRepository.save(activityPO);
// 🛡️ 防腐:处理领域事件(JPA 不知道的概念)
aggregate.clearDomainEvents();
}
@Override
public Optional<ActivityAggregate> findById(ActivityId activityId) {
// 🛡️ 防腐:ActivityId → String
Optional<ActivityPO> activityPO = activityRepository.findByActivityId(
activityId.getValue() // 值对象转换
);
// 🛡️ 防腐:PO → Aggregate
return activityPO.map(activityConverter::poToAggregate);
}
}防腐职责:
✅ 转换领域对象(Aggregate)↔ 持久化对象(PO)
✅ 转换值对象(ActivityId)↔ 原始类型(String)
✅ 处理领域事件(Domain Event)
✅ 隔离领域逻辑和持久化技术
第二层防腐:ActivityJpaRepository
java
// 防腐点 2:隔离 JPA 框架
@Repository
public interface ActivityJpaRepository extends JpaRepository<ActivityPO, Long> {
// 🛡️ 防腐:封装 JPA 方法命名规则
Optional<ActivityPO> findByActivityId(String activityId);
// 🛡️ 防腐:封装 JPQL 查询
@Query("SELECT a FROM ActivityPO a WHERE a.status = 'PUBLISHED'")
List<ActivityPO> findPublishedActivities();
}防腐职责:
✅ 封装 Spring Data JPA 框架
✅ 如果换成 MyBatis,只需修改这一层
✅ 隔离 SQL 方言和数据库特性
✅ 提供统一的数据访问接口
问题 2:ActivityJpaRepository 的写法是否正确?
✅ 正确的部分
方法命名查询(Method Name Query)
java// ✅ 正确:利用 Spring Data JPA 的方法命名规则 Optional<ActivityPO> findByActivityId(String activityId); List<ActivityPO> findByCreatorId(String creatorId); List<ActivityPO> findByStatus(String status);优点:
不需要写 SQL,JPA 自动生成
简单查询推荐使用
类型安全
@Query 注解(复杂查询)
java// ✅ 正确:复杂查询使用 @Query @Query("SELECT a FROM ActivityPO a WHERE a.status = 'PUBLISHED' AND a.isDeleted = false") List<ActivityPO> findPublishedActivities(); @Query("SELECT a FROM ActivityPO a WHERE a.status = 'PUBLISHED' AND a.startTime <= :now " + "AND a.endTime >= :now AND a.isDeleted = false") List<ActivityPO> findOngoingActivities(@Param("now") LocalDateTime now);优点:
复杂条件更清晰
可以优化查询性能
支持动态参数